<?php
	abstract class Hook {
		protected static $hooks = array();
		
		public static function create($hook_name,$hook_multiple=true){
			if(!isset(Hook::$hooks[$hook_name][($hook_multiple) ? "multiple" : "simple"])){
					Hook::$hooks[$hook_name][($hook_multiple) ? "multiple" : "simple"] = ($hook_multiple) ? array() : function(){};
			}
		}
		
		//Creation de hook protégé => Ne peut pas être supprimé par Hook::delete et Hook::delete_multihook_element
		public static function protected_create($hook_name,$hook_multiple=true){
			if(!isset(Hook::$hooks[$hook_name][($hook_multiple) ? "p_multiple" : "p_simple"])){
					Hook::$hooks[$hook_name][($hook_multiple) ? "p_multiple" : "p_simple"] = ($hook_multiple) ? array() : function(){};
			}
		}
		
		public static function add($hook_name,Closure $hook_action,$priority=0,$name=""){
			$priority = (is_string($priority)&&!ctype_digit($priority)) ? "0" : strval($priority);
			$name = ($name=="") ? Hook::getNumHookRegistered($hook_name) : $name;
			if(isset(Hook::$hooks[$hook_name]["multiple"]))
				Hook::$hooks[$hook_name]["multiple"][$priority][$name] = $hook_action;	
			else if(isset(Hook::$hooks[$hook_name]["simple"]))
				Hook::$hooks[$hook_name]["simple"] = $hook_action;
			else if(isset(Hook::$hooks[$hook_name]["p_multiple"]))
				Hook::$hooks[$hook_name]["p_multiple"][$priority][$name] = $hook_action;	
			else if(isset(Hook::$hooks[$hook_name]["p_simple"]))
				Hook::$hooks[$hook_name]["p_simple"] = $hook_action;
		}
		
		public static function delete($hook_name){
			if(isset(Hook::$hooks[$hook_name]["multiple"]))
				unset(Hook::$hooks[$hook_name]["multiple"]);	
			else if(isset(Hook::$hooks[$hook_name]["simple"]))
				unset(Hook::$hooks[$hook_name]["simple"]);
		}
		
		public static function delete_multihook_element($hook_name,$element=0,$index=-1){
			if(isset(Hook::$hooks[$hook_name]["multiple"])){
				if($index>-1)
					unset(Hook::$hooks[$hook_name]["multiple"][$element][$index]);
				else
					unset(Hook::$hooks[$hook_name]["multiple"][$element]);	
			}
		}
		
		public static function call(){
			//error_reporting(E_NOTICE);
			$args = func_get_args();
			$hook_name = (!empty($args[0]) ? $args[0] : "");
			unset($args[0]);
			
			if(isset(Hook::$hooks[$hook_name]["multiple"])){
				$return = null;
				ksort(Hook::$hooks[$hook_name]["multiple"]);
					foreach(Hook::$hooks[$hook_name]["multiple"] as $hooks){
						foreach($hooks as $hook)
							$return = ($return==null) ? call_user_func_array($hook,$args) : $return.call_user_func_array($hook,$args);
					}
				return $return;
			}else if(isset(Hook::$hooks[$hook_name]["simple"])){
					return call_user_func_array(Hook::$hooks[$hook_name]["simple"],$args);
			}else if(isset(Hook::$hooks[$hook_name]["p_multiple"])){
				$return = '';
				ksort(Hook::$hooks[$hook_name]["p_multiple"]);
					foreach(Hook::$hooks[$hook_name]["p_multiple"] as $hooks){
						foreach($hooks as $hook)
							$return = ($return==null) ? call_user_func_array($hook,$args) : $return.call_user_func_array($hook,$args);
					}
				return $return;
			}else if(isset(Hook::$hooks[$hook_name]["p_simple"])){
					return call_user_func_array(Hook::$hooks[$hook_name]["p_simple"],$args);
			}
		}
		
		public static function exists($hook_name){
			if(isset(Hook::$hooks[$hook_name]["multiple"]))
				return true;
			else if(isset(Hook::$hooks[$hook_name]["simple"]))
				return true;
			else if(isset(Hook::$hooks[$hook_name]["p_multiple"]))
				return true;
			else if(isset(Hook::$hooks[$hook_name]["p_simple"]))
				return true;
			else
				return false;	
		}
		
		public static function getNumHookRegistered($hook_name=""){
			$num = 0;
			if($hook_name==""){
				foreach(Hook::$hooks as $hooks){
					$num=count($hooks["multiple"]);
					$num+=isset($hooks["simple"]) ? 1 : 0;
					$num+=isset($hooks["p_simple"]) ? 1 : 0;
					$num=count($hooks["p_multiple"]);
				}
			}else{
				if(isset(Hook::$hooks[$hook_name])){
					foreach(Hook::$hooks[$hook_name] as $hooks){
						if(is_array($hooks))
							$num = count($hooks);
						else
							$num += 1;
					}
				}
			}
			return $num;
		}
	}
?>